package user

import (
	"context"
	"github.com/go-kratos/kratos/v2/errors"
	"github.com/go-kratos/kratos/v2/log"
	userApi "go-skeleton/api/v1/service/user"
	"go-skeleton/app/v1/service/internal/data/ent"
)

var (
	ErrSystemErr          = errors.NotFound(userApi.ErrorReason_SYSTEM_ERR.String(), "服务器开小差了")
	ErrUserNotFound       = errors.NotFound(userApi.ErrorReason_USER_NOT_FOUND.String(), "用户不存在")
	ErrUserRegistered     = errors.NotFound(userApi.ErrorReason_USER_REGISTERED.String(), "用户已注册")
	ErrVerifyCodeFrequent = errors.NotFound(userApi.ErrorReason_VERIFY_CODE_FREQUENT.String(), "验证码发送频繁")
	ErrVerifyCodeErr      = errors.NotFound(userApi.ErrorReason_VERIFY_CODE_ERROR.String(), "验证码错误")
	ErrPasswordErr        = errors.NotFound(userApi.ErrorReason_PASSWORD_ERROR.String(), "密码错误")
)

// UserRepo is a Greater repo.
type UserRepo interface {
	Save(context.Context, *ent.User) (*ent.User, error)
	Update(context.Context, *ent.User) (*ent.User, error)
	FindByID(context.Context, int64) (*ent.User, error)
	FindByPhone(context.Context, string) (*ent.User, error)
	ListUser(context.Context, int64, int64) ([]*ent.User, error)
	SendCode(context.Context, string) error
	VerifyCode(context.Context, string, string) (bool, error)
	VerifyPassword(context.Context, *ent.User) (bool, error)
}

// UserBiz
type UserBiz struct {
	repo UserRepo
	log  *log.Helper
}

// NewUserBiz
func NewUserBiz(repo UserRepo, logger log.Logger) *UserBiz {
	return &UserBiz{repo: repo, log: log.NewHelper(log.With(logger, "module", "biz/user"))}
}

// CreateUser creates a User, and returns the new User.
func (uc *UserBiz) CreateUser(ctx context.Context, g *ent.User) (*ent.User, error) {
	return uc.repo.Save(ctx, g)
}

func (uc *UserBiz) FindByID(ctx context.Context, id int64) (*ent.User, error) {
	return uc.repo.FindByID(ctx, id)
}

func (uc *UserBiz) FindByPhone(ctx context.Context, phone string) (*ent.User, error) {
	return uc.repo.FindByPhone(ctx, phone)
}

func (uc *UserBiz) SendCode(ctx context.Context, phone string) error {
	return uc.repo.SendCode(ctx, phone)
}

func (uc *UserBiz) VerifyCode(ctx context.Context, phone, code string) error {
	ok, err := uc.repo.VerifyCode(ctx, phone, code)
	if err != nil {
		return err
	}

	if !ok {
		return ErrVerifyCodeErr
	}

	return nil
}

func (uc *UserBiz) VerifyPassword(ctx context.Context, u *ent.User) error {
	ok, err := uc.repo.VerifyPassword(ctx, u)
	if err != nil {
		return err
	}

	if !ok {
		return ErrPasswordErr
	}

	return nil
}
